1 /**
2 * @author Stéphane Roucheray
3 * @extends jQuery
4 */
5
6 jQuery.fn.dynamicForm = function (plusElmnt, minusElmnt, options){
7 var source = jQuery(this),
8 minus = jQuery(minusElmnt),
9 plus = jQuery(plusElmnt),
10 template = source.clone(true),
11 fieldId = 0,
12 formFields = "input, checkbox, select, textarea",
13 insertBefore = source.next(),
14 clones = [],
15 defaults = {
16 duration:1000
17 };
18
19 // Extend default options with those provided
20 options = $.extend(defaults, options);
21
22 isPlusDescendentOfTemplate = source.find("*").filter(function(){
23 return this == plus.get(0);
24 });
25
26 isPlusDescendentOfTemplate = isPlusDescendentOfTemplate.length > 0 ? true : false;
27
28 function normalizeElmnt(elmnt){
29 elmnt.find(formFields).each(function(){
30 var nameAttr = jQuery(this).attr("name"),
31 idAttr = jQuery(this).attr("id");
32
33 /* Normalize field name attributes */
34 if (!nameAttr) {
35 jQuery(this).attr("name", "field" + fieldId + "[]");
36 }
37
38 if (!/\[\]$/.exec(nameAttr)) {
39 jQuery(this).attr("name", nameAttr + "[]");
40 }
41
42 /* Normalize field id attributes */
43 if (idAttr) {
44 /* Normalize attached label */
45 jQuery("label[for='"+idAttr+"']").each(function(){
46 jQuery(this).attr("for", idAttr + fieldId);
47 });
48
49 jQuery(this).attr("id", idAttr + fieldId);
50 }
51 fieldId++;
52 });
53 };
54
55 /* Hide minus element */
56 minus.hide();
57
58 /* If plus element is within the template */
59 if (isPlusDescendentOfTemplate) {
60 function clickOnPlus(event){
61 var clone,
62 currentClone = clones[clones.length -1] || source;
63 event.preventDefault();
64
65 /* On first add, normalize source */
66 if (clones.length == 0) {
67 normalizeElmnt(source);
68 currentClone.find(minusElmnt).hide();
69 currentClone.find(plusElmnt).hide();
70 }else{
71 currentClone.find(plusElmnt).hide();
72 }
73
74 /* Clone template and normalize it */
75 clone = template.clone(true).insertAfter(clones[clones.length - 1] || source);
76 normalizeElmnt(clone);
77
78 /* Normalize template id attribute */
79 if (clone.attr("id")) {
80 clone.attr("id", clone.attr("id") + clones.length);
81 }
82
83
84 plus = clone.find(plusElmnt);
85 minus = clone.find(minusElmnt);
86
87 minus.get(0).removableClone = clone;
88 minus.click(clickOnMinus);
89 plus.click(clickOnPlus);
90
91 if (options.limit && (options.limit - 2) > clones.length) {
92 plus.show();
93 }else{
94 plus.hide();
95 }
96
97 clones.push(clone);
98 }
99
100 function clickOnMinus(event){
101 event.preventDefault();
102
103 if (this.removableClone.effect && options.removeColor) {
104 that = this;
105 this.removableClone.effect("highlight", {
106 color: options.removeColor
107 }, options.duration, function(){that.removableClone.remove();});
108 } else {
109
110 this.removableClone.remove();
111 }
112 clones.splice(clones.indexOf(this.removableClone),1);
113 if (clones.length == 0){
114 source.find(plusElmnt).show();
115 }else{
116 clones[clones.length -1].find(plusElmnt).show();
117 }
118 }
119
120 /* Handle click on plus */
121 plus.click(clickOnPlus);
122
123 /* Handle click on minus */
124 minus.click(function(event){
125
126 });
127
128 }else{
129 /* If plus element is out of the template */
130 /* Handle click on plus */
131 plus.click(function(event){
132 var clone;
133
134 event.preventDefault();
135
136 /* On first add, normalize source */
137 if (clones.length == 0) {
138 normalizeElmnt(source);
139 jQuery(minusElmnt).show();
140 }
141
142 /* Clone template and normalize it */
143 clone = template.clone(true).insertAfter(clones[clones.length - 1] || source);
144 if (clone.effect && options.createColor) {
145 clone.effect("highlight", {color:options.createColor}, options.duration);
146 }
147 normalizeElmnt(clone);
148
149 /* Normalize template id attribute */
150 if (clone.attr("id")) {
151 clone.attr("id", clone.attr("id") + clones.length);
152 }
153 if (options.limit && (options.limit - 3) < clones.length) {
154 plus.hide();
155 }
156 clones.push(clone);
157 });
158
159 /* Handle click on minus */
160 minus.click(function(event){
161 event.preventDefault();
162 var clone = clones.pop();
163 if (clones.length >= 0) {
164 if (clone.effect && options.removeColor) {
165 that = this;
166 clone.effect("highlight", {
167 color: options.removeColor, mode:"hide"
168 }, options.duration, function(){clone.remove();});
169 } else {
170 clone.remove();
171 }
172 }
173 if (clones.length == 0) {
174 jQuery(minusElmnt).hide();
175 }
176 plus.show();
177 });
178 }
179
180 };